package com.iweb.oasys.component;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.iweb.oasys.conf.SysConstants;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 封装一个 JdbcConnectionPool Jdbc连接池类
 * 用druid管理数据库连接池
 */
public class JdbcConnectionPool {
    /* 构造方法私有化,该类成员全是静态成员*/
    private JdbcConnectionPool(){}
    /* 声明线程变量connectionThreadLocal存放当前获取的connection连接对象 */
    private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
    /* 声明druidDataSource全局变量,用来保存指向连接池对象的引用,所有方法都可以访问这个引用 */
    private static DruidDataSource druidDataSource = null;
    /* 当前类被加载时执行的静态代码块 */
    static
    {
        Properties prop = loadPropertiesFile(SysConstants.JDBC_CONF_FILE);
        try {
            /* 用配置文件对象作为参数, 创建数据库连接池,用dataSource引用保存连接池对象 */
            /* 把dataSource声明为全局静态变量, 否则其他方法中无法访问这个连接池 */
            druidDataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(prop);
            /* 调用连接池的init()方法初始化连接池 */
            druidDataSource.init();
            /* 第一次调用获取连接的方法也会初始化连接池 */
            // Connection connection = druidDataSource.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    private static Properties loadPropertiesFile(String filePath)
    {
        if(null == filePath || filePath.equals(""))
        {
            throw new IllegalArgumentException("Properties file path can not be null"+filePath);
        }
        Properties prop = new Properties();
        try {
            /* 根据配置文件路径加载配置文件, 返回一个Properties对象 */
            prop.load(JdbcConnectionPool.class.getClassLoader().getResourceAsStream(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  prop;
    }

    /* 暴露一个静态方法给外部,从连接池中拿出一个连接对象,然后线程变量中,任何返回给外部 */
    public static Connection getConnection()
    {
        /* 从线程变量中获取connection */
        Connection connection = connectionThreadLocal.get();
        try
        {
            if(null == connection) /*如果线程变量中获取的connection是null*/
            {
                // 从连接池中取一个connection, 连接池会返回一个空闲的connection
                connection =  druidDataSource.getConnection();
                connectionThreadLocal.set(connection);         // 放入线程变量中
            }
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
        return  connection; // 返回这个connection, 这个connection放入了线程变量中,所以是线程安全的
    }

    /* 暴露一个静态方法给外部用来关闭当前线程中的connection对象 */
    /* 如果连接对象不关闭的话,当100个连接对象都被使用后,连接池将没有新的连接对象,处于永久等待状态 */
    public static void closeConnection()
    {
        /* 从线程变量中取出connection */
        Connection connection = connectionThreadLocal.get();
        try {
            if(null!=connection) /* 如果connection不是null,就close()关闭, 并且从线程变量中移除*/
            {
                connection.close();
                connectionThreadLocal.remove();
            }
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
    }
    /* 暴露一个开启事务的方法, 让当前连接对象开启事务 */
    public static void startTransaction()
    {
        Connection connection = connectionThreadLocal.get();
        try {
            if(null == connection)
            {
                connection = getConnection(); // 如果线程变量中没有connection,调用上面的getConnection方法获取connection
            }
            connection.setAutoCommit(false); // 关闭自动提交,即为当前连接开启事务
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
    }
    /* 暴露一个提交事务的方法 */
    public static void commit()
    {
        Connection connection = connectionThreadLocal.get();
        try {
            if(null!=connection)
            {
                connection.commit();
            }
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
    }
    /* 暴露一个回滚事务的方法 */
    public static void rollback()
    {
        Connection connection = connectionThreadLocal.get();
        try {
            if(null!=connection)
            {
                connection.rollback();
            }
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
    }
}
